#!/usr/bin/python2
# -*- coding: utf-8 -*-
# Name:     viewers.py
# Author:   xiooli <xioooli[at]yahoo.com.cn>
# Version:  111108

from PySide import QtCore, QtGui, QtSvg
import re
from dialogs import MyErrorDialog
from .. utils import fixsvg, SVG_UNKNOWN_STRUC
from .. mol import Mol2pic
from .. spectra import MS

try:
    from .. utils import tr
except:
    tr = lambda msg: msg

svgrenderer = QtSvg.QSvgRenderer()

def svg2qimage(svg, qimage = QtGui.QImage(), fill = QtCore.Qt.white):
    qimage.fill(fill)
    painter = QtGui.QPainter()
    painter.begin(qimage)
    svgrenderer.load(QtCore.QByteArray(fixsvg(svg)))
    svgrenderer.render(painter)
    painter.end()
    return qimage

class SvgViewer(QtGui.QWidget):
    def __init__(self, svg, parent = None, size = QtCore.QSize(400, 400)):
        QtGui.QWidget.__init__(self, parent)
        self.parent = parent
        self.svg = svg
        self.painter = QtGui.QPainter()
        self.resize(size)

    def resizeEvent(self, event):
        self.redraw(event.size())

    def redraw(self, size = None):
        if not size:
            size = self.size()
        self.qimage = svg2qimage(self.svg,
                QtGui.QImage(size, QtGui.QImage.Format_ARGB32))
        self.repaint()

    def paintEvent(self, event):
        self.painter.begin(self)
        self.painter.drawImage(0, 0, self.qimage)
        self.painter.end()

    def closeEvent(self, event):
        event.accept()

class MolViewer(QtGui.QMainWindow):
    sigMolChanged = QtCore.Signal(object)
    def __init__(self, mol_string = '', parent = None, size = QtCore.QSize(500, 500)):
        QtGui.QMainWindow.__init__(self, parent)
        self.blank_mol_string = '''[NO NAME]
  XXXXX  1121111642112D
Created with XXXXX
  0  0  0  0  0  0            999 V2000
M  END
'''
        if not mol_string:
            self.mol_string = self.blank_mol_string
        else:
            self.mol_string = mol_string.replace('\r', '').replace('\\n', '\n')

        self.mark_idx = 0
        self.letters = (
                'a', 'b', 'c', 'd', 'e',
                'f', 'g', 'h', 'i', 'j', 'k',
                'l', 'm', 'n', 'o', 'p', 'q',
                'r', 's', 't', 'tr(', ')v', 'w',
                'x', 'y', 'z')

        self.mol_marks = [ 'J' + i for i in self.letters ]
        self.regx_mark_mol = re.compile(r'(J[a-z])|(\*)')

        self.file_selector = QtGui.QFileDialog(self)
        self.error_dialog = MyErrorDialog()
        self.plain_text_edit = QtGui.QPlainTextEdit()
        self.plain_text_edit.resize(QtCore.QSize(500, 350))

        self.groupBox = QtGui.QGroupBox(self)
        self.groupBox.setTitle("")

        self.svg = SVG_UNKNOWN_STRUC
        self.mol_viewer = SvgViewer(self.svg, self.groupBox)
        self.mol_viewer.setMinimumSize(QtCore.QSize(450, 450))
        self.mol_viewer.setMaximumSize(QtCore.QSize(800, 800))
        self.setMinimumSize(QtCore.QSize(450, 450))

        self.vl = QtGui.QVBoxLayout(self.groupBox)
        self.setCentralWidget(self.groupBox)
        self.vl.addWidget(self.mol_viewer)

        self.save_btn = QtGui.QPushButton(self.groupBox)
        self.save_btn.setText(tr('Save'))
        self.open_btn = QtGui.QPushButton(self.groupBox)
        self.open_btn.setText(tr('Open'))
        self.mark_mol_btn = QtGui.QPushButton(self.groupBox)
        self.mark_mol_btn.setText(tr('Mark mol'))
        self.auto_layout_btn = QtGui.QPushButton(self.groupBox)
        self.auto_layout_btn.setText(tr('Auto layout'))
        self.print_mol_btn = QtGui.QPushButton(self.groupBox)
        self.print_mol_btn.setText(tr('Show MOL text'))

        self.hl = QtGui.QHBoxLayout()
        self.vl.addLayout(self.hl)
        self.hl.addWidget(self.save_btn)
        self.hl.addWidget(self.open_btn)
        self.hl.addWidget(self.mark_mol_btn)
        self.hl.addWidget(self.auto_layout_btn)
        self.hl.addWidget(self.print_mol_btn)

        self.resize(size)

        self.islayout = False
        self.layout()

        self._connect_signals()

    def _connect_signals(self):
        self.save_btn.clicked.connect(self._on_save_btn_clicked)
        self.open_btn.clicked.connect(self._on_open_btn_clicked)
        self.mark_mol_btn.clicked.connect(self._on_mark_mol_btn_clicked)
        self.auto_layout_btn.clicked.connect(self._on_auto_layout)
        self.print_mol_btn.clicked.connect(self._on_print_mol_btn_clicked)

    def hide_btns(self, ishide = True):
        if ishide:
            self.save_btn.hide()
            self.open_btn.hide()
            self.mark_mol_btn.hide()
            self.auto_layout_btn.hide()
            self.print_mol_btn.hide()
        else:
            self.save_btn.show()
            self.open_btn.show()
            self.mark_mol_btn.show()
            self.auto_layout_btn.show()
            self.print_mol_btn.show()

    def mark_mol_repl(self, g):
        if self.mark_idx >= len(self.mol_marks):
            self.mark_idx = 0
        mark = self.mol_marks[self.mark_idx]
        self.mark_idx += 1
        return mark

    def layout(self):
        if not self.mol_string:
            self.svg = '<svg></svg>'
        elif self.mol_string != self.blank_mol_string:
            self.svg = Mol2pic(self.mol_string).to_pic('svg', self.islayout)
            self.mol_string = Mol2pic(self.mol_string).to_mol(self.islayout)
        self.mol_viewer.svg = self.svg
        self.mol_viewer.redraw()

    def _on_auto_layout(self):
        self.islayout = True
        self.layout()
        self.islayout = False
        self.sigMolChanged.emit(self.mol_string)

    def set_mol(self, mol_string):
        self.mol_string = mol_string.replace('\r', '').replace('\\n', '\n')
        self.layout()

    def get_mol(self):
        return self.mol_string

    def _on_save_btn_clicked(self):
        file_name = self.file_selector.getSaveFileName(self, tr('Save to MOL file'), '',
            tr('*.mol (MDL/MOL file)(*.mol);;*.* (All types of file)(*)'))[0]
        if file_name != '':
            if not file_name.endswith('.mol'):
                file_name = file_name + '.mol'
            try:
                open(file_name, 'w').write(self.mol_string)
            except Exception, e:
                self.error_dialog.setText(str(e).decode('utf8'))
                self.error_dialog.exec_()

    def _on_open_btn_clicked(self):
        file_name = self.file_selector.getOpenFileName(self, tr('Choose MOL file'), '',
            tr('*.mol (MDL/MOL file)(*.mol);;*.* (All types of file)(*)'))[0]
        if file_name != '':
            if not file_name.endswith('.mol'):
                self.error_dialog.setText(tr('Is not a MOL file!'))
                self.error_dialog.exec_()
                return
            try:
                mol = open(file_name, 'rb').read().replace('\r', '')
                self.set_mol(mol)
                self.sigMolChanged.emit(mol)
            except Exception, e:
                self.error_dialog.setText(str(e).decode('utf8'))
                self.error_dialog.exec_()

    def _on_mark_mol_btn_clicked(self):
        self.mark_idx = 0
        self.set_mol(self.regx_mark_mol.sub(self.mark_mol_repl, self.mol_string))

    def _on_print_mol_btn_clicked(self):
        self.plain_text_edit.setWindowTitle(tr('MOL text'))
        self.plain_text_edit.setPlainText(self.get_mol())
        self.plain_text_edit.show()

class MSViewer(QtGui.QMainWindow):
    def __init__(self, ms_string = '', parent = None, size = QtCore.QSize(500, 250)):
        QtGui.QMainWindow.__init__(self, parent)

        self.ms_string = ms_string

        self.file_selector = QtGui.QFileDialog(self)
        self.error_dialog = MyErrorDialog()
        self.plain_text_edit = QtGui.QPlainTextEdit()
        self.plain_text_edit.resize(QtCore.QSize(500, 350))

        self.groupBox = QtGui.QGroupBox(self)
        self.groupBox.setTitle("")

        self.resolution = 0
        self.ms_obj = MS(spectra = self.ms_string)

        self.svg = '<svg></svg>'
        self.ms_viewer = SvgViewer(self.svg, self.groupBox)
        #self.ms_viewer.setMinimumSize(QtCore.QSize(400, 200))
        self.ms_viewer.setMaximumSize(QtCore.QSize(1000, 500))
        self.setMaximumSize(QtCore.QSize(1000, 600))
        #self.setMinimumSize(QtCore.QSize(450, 225))

        self.vl = QtGui.QVBoxLayout(self.groupBox)
        self.setCentralWidget(self.groupBox)
        self.vl.addWidget(self.ms_viewer)

        self.save_btn = QtGui.QPushButton(self.groupBox)
        self.save_btn.setText(tr('Save'))
        self.open_btn = QtGui.QPushButton(self.groupBox)
        self.open_btn.setText(tr('Open'))
        self.print_ms_btn = QtGui.QPushButton(self.groupBox)
        self.print_ms_btn.setText(tr('Show MS text'))

        self.hl = QtGui.QHBoxLayout()
        self.vl.addLayout(self.hl)
        self.hl.addWidget(self.save_btn)
        self.hl.addWidget(self.open_btn)
        self.hl.addWidget(self.print_ms_btn)

        self.resize(size)

        self.layout()

        self._connect_signals()

    def _connect_signals(self):
        self.save_btn.clicked.connect(self._on_save_btn_clicked)
        self.open_btn.clicked.connect(self._on_open_btn_clicked)
        self.print_ms_btn.clicked.connect(self._on_print_ms_btn_clicked)

    def set_iso_width(self, iso_width):
        try:
            self.ms_obj.iso_width = float(iso_width)
        except:
            pass

    def set_deviation(self, deviation):
        try:
            self.ms_obj.deviation = float(deviation)
        except:
            pass

    def set_noise_level(self, noise_level):
        try:
            self.ms_obj.noise_level = float(noise_level)
        except:
            pass

    def hide_btns(self, ishide = True):
        if ishide:
            self.save_btn.hide()
            self.open_btn.hide()
            self.print_ms_btn.hide()
        else:
            self.save_btn.show()
            self.open_btn.show()
            self.print_ms_btn.show()

    def layout(self):
        if self.ms_string:
            self.ms_obj = MS(spectra = self.ms_string)
            self.ms_obj.resolution = self.resolution
            self.svg = self.ms_obj.gen_ms_svg()
            self.spectra_txt = self.ms_obj.spectra_txt
            self.ms_viewer.svg = self.svg
            self.ms_viewer.redraw()
        else:
            self.ms_viewer.svg = '<svg></svg>'
            self.ms_viewer.redraw()

    def set_resulotion(self, resolution = 0):
        if resolution == 0:
            self.resolution = 0
        elif resolution == 1:
            self.resolution = 1
        self.layout()

    def set_ms(self, ms_string):
        self.ms_string = ms_string
        self.layout()

    def get_ms(self):
        return self.spectra_txt

    def _on_save_btn_clicked(self):
        file_name = self.file_selector.getSaveFileName(self, tr('Save MS to text file'), '',
            tr('*.txt (*.txt);;*.* (All types of file)(*)'))[0]
        if file_name != '':
            if not file_name.endswith('.txt'):
                file_name = file_name + '.txt'
            try:
                open(file_name, 'w').write(self.ms_string)
            except Exception, e:
                self.error_dialog.setText(str(e).decode('utf8'))
                self.error_dialog.exec_()

    def _on_open_btn_clicked(self):
        file_name = self.file_selector.getOpenFileName(self, tr('Open MS file'), '',
            tr('*.txt (*.txt);;*.* (All types of file)(*)'))[0]
        if file_name != '':
            try:
                ms = open(file_name, 'rb').read().replace('\r', '')
                self.set_ms(ms)
            except Exception, e:
                self.error_dialog.setText(str(e).decode('utf8'))
                self.error_dialog.exec_()

    def _on_print_ms_btn_clicked(self):
        self.plain_text_edit.setWindowTitle(tr('MS text'))
        self.plain_text_edit.setPlainText(self.get_ms())
        self.plain_text_edit.show()


if __name__ == "__main__":
    import sys

    app = QtGui.QApplication(sys.argv)
    #mv = MolViewer(open('../a.mol').read())
    #mv.show()
    ms = MSViewer()
    ms.show()
    sys.exit(app.exec_())
